知识点名称:线程的基本用法

编号: K10-1

前驱知识点编号:K6-1,K3-1

作者:

讲义内容:

  1. 线程和进程的基本概念及关系

大家在《操作系统原理》中都学习过进程和线程的基本概念以及如何调度,现在,我们大概来回忆一下, 我们知道:一个进程就是一个执行中的程序,而每一个进程都有自己独立的一块内存空间、一组系统资源,且每一个进程的内部数据和状态都是完全独立的。而一个进程中可以同时运行多个不同的线程(也可以理解成程序中的不同线索),执行不同的任务。也就是宏观上一个程序的多行语句可以看上去几乎在同一时间内同时运行。

线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制。但与进程不同的是,同类的多个线程共享一块内存空间和一组系统资源,所以系统在各个线程之间切换时,资源占用要比进程小得多,正因如此,线程也被称为轻量级进程。一个进程中可以包含多个线程。

  1. Android中的多线程

多线程应用在Android平台中很广泛,这是因为,Android中对每一个App的运行都看做一个进程,而这个进程中的主线程,就是UI线程(管理用户界面的线程),也就是我们打开一个App时可以看到界面的这个线程,主线程主要负责控制UI界面的显示、更新和与用户交互的事件响应,在这个主线程内不能有太长时间的阻塞,线程阻塞超过5秒后就会报程序无响应(即ANR: Application Not Responding)的错误。因此一些复杂的、耗时的操作必须开启新的线程去操作,如:IO操作(网络操作,文件操作,数据库操作等),复杂的运算工作,消息接收中的耗时操作等,这样来避免阻塞主线程。下面我们通过具体实例来演示使用多线程和不使用多线程对用户体验的影响。

public class MainActivity extends ActionBarActivity {
     private Button bt1,bt2;
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        bt1=(Button) this.findViewById(R.id.button1);
        bt2=(Button) this.findViewById(R.id.button2);
        bt1.setOnClickListener(new OnClickListener(){    
            public void onClick(View v) {
            try {
            Thread.sleep(1000);
            System.out.println(">>>>>>>>单线程,注意观察阻塞现象");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }    
            }});
    bt2.setOnClickListener(new OnClickListener(){
        public void onClick(View v) {
            new Thread(){
            public void run()
                {
                try {
                Thread.sleep(1000);
                System.out.println(">>>>>>>>多线程,无阻塞现象");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    }
                }
            }.start();
       }
    );
    }  
}

由于android的ui线程操作是单线程模式,它并不是安全的,因此,这种模式要求和用户直接进行界面交互的操作都必须在ui线程中进行才可以。而单线程模式下的编程需要注意:不要阻塞ui线程、确保只在ui线程中访问ui组件。但是上例中单线程情况下会看到按钮按下后一秒才能弹起,直到该按钮的单击事件执行完后,才能操作界面上别的组件,也就是出现的阻塞现象,这样会影响用户使用体验。但是通过创建一个新线程的方式,就可以在线程中并发的执行一个具体的操作或者是某一项任务而不会影响到主线程的表现,主线程不会因为它而产生卡死或阻塞的状态,从而提高用户体验的效果。因此,我们让所有可能耗时的操作都放到其他线程去处理。而主线程的事件处理不能太耗时,否则后续的事件无法在5秒内得到响应,就会弹出ANR对话框。像Activity的生命周期方法中的onCreate()、onStart()、onResume()等以及事件处理方法onClick()、onItemClick()等都会在主线程中运行,因此,它们的执行时间决定了应用首页打开的时间,就要尽量把不必要的操作放到其它线程去处理。

另外,当用户与应用交互时,事件处理方法的执行快慢决定了应用的响应性是否良好,一般分为同步和异步两种情况:

1) 同步,需要等待返回结果。例如用户点击了登陆按钮,需要等待服务端返回结果,那么需要有一个进度条来提示用户程序正在运行没有死掉。一般与服务端交互的都要有进度条,例如系统自带的浏览器,URL跳转时会有进度条。

2) 异步,不需要等待返回结果。例如微博中的收藏功能,点击完收藏按钮后是否成功执行完成后告诉用户就行了,不必等待,就可以用异步实现。

多线程的本质就是异步处理,直观一点说就是不要让用户感觉到“很卡”。因此,对比较耗时的操作,就需要放到其他线程中处理,等处理完成后,再通知主线程刷新界面,这就涉及到线程间通讯问题,在Android中常见的其他线程与Main线程通讯的方式有两种: 1) 使用Handler,2) 使用AsyncTask.后面的章节将做详细的介绍。

results matching ""

    No results matching ""